
;	The following code tests the RAM on the 2500 A.D. test board.
;	RAM below 1000h is not tested because the stack, page 0 and memory
;	mapped I/O reside there, and the MMU can only map 4K boundaries.

		.memory_test_section

;	Test the boards RAM.

ZERO_TEST:	.equal	1			;all zero's test
ONE_TEST:	.equal	2			;all one's test
INC_TEST:	.equal	3			;increment test type
DEC_TEST:	.equal	4			;decrement test type
ALT_TEST:	.equal	5			;alternating 1's & 0's test
COM_TEST:	.equal	6			;complemented 1's & 0's test

;	All zero's data test

memory_test:	ldx	#.low.zero_test_msg	;load addr of test msg
		ldy	#.high.zero_test_msg
		jsr	string_out		;output message name
		ldx	#ZERO_TEST		;zero's data test
		jsr	ram_test
		and	#ffh			;check for error
		bne	?memory_error
		jsr	output_passed		;output passed message

;	All one's data test

		ldx	#.low.one_test_msg	;load addr of test msg
		ldy	#.high.one_test_msg
		jsr	string_out		;output message name
		ldx	#ONE_TEST		;one's data test
		jsr	ram_test
		and	#ffh			;check for error
		bne	?memory_error
		jsr	output_passed		;output passed message

;	Increment data test

		ldx	#.low.inc_test_msg	;load addr of test msg
		ldy	#.high.inc_test_msg
		jsr	string_out		;output message name
		ldx	#INC_TEST		;increment data test
		jsr	ram_test
		and	#ffh			;check for error
		bne	?memory_error
		jsr	output_passed		;output passed message

;	Decrement data test

		ldx	#.low.dec_test_msg	;load addr of test msg
		ldy	#.high.dec_test_msg
		jsr	string_out		;output message name
		ldx	#DEC_TEST		;decrement data test
		jsr	ram_test
		and	#ffh			;check for error
		bne	?memory_error
		jsr	output_passed		;output passed message

;	Alternating 1's & 0's test

		ldx	#.low.alt_test_msg	;load addr of test msg
		ldy	#.high.alt_test_msg
		jsr	string_out		;output message name
		ldx	#ALT_TEST		;alternating 1's & 0's test
		jsr	ram_test
		and	#ffh			;check for error
		bne	?memory_error
		jsr	output_passed		;output passed message

;	Complemented 1's & 0's test

		ldx	#.low.com_test_msg	;load addr of test msg
		ldy	#.high.com_test_msg
		jsr	string_out		;output message name
		ldx	#COM_TEST		;complemented 1's & 0's test
		jsr	ram_test
		and	#ffh			;check for error
		bne	?memory_error
		jsr	output_passed		;output passed message

;	Return to routine that called the memory test

		lda	#CR
		jsr	polled_serial_out
		lda	#LF
		jsr	polled_serial_out
		rts				;memory test passed

?memory_error:	jmp	?memory_error		;just loop if error

;	Replace address with 'Passed' message.

output_passed:	ldy	#31			;load # of backspaces to output
?loop:		lda	#BS			;back up before 'Checking Ram
		jsr	polled_serial_out	; Location' message
		dey
		bne	?loop
		ldx	#.low.passed_msg	;load addr of passed msg
		ldy	#.high.passed_msg
		jsr	string_out		;output passed message
		rts

;	Initialize the test data register '__oper1', depending on the test
;	number in 'x'.

init_test_data:	cpx	#ZERO_TEST		;zero's data test ?
		bne	?next1
		lda	#0			;init data register
		sta	__oper1
		sta	__oper1+1
		rts
?next1:		cpx	#ONE_TEST		;one's data test ?
		bne	?next2
		lda	#ffh			;init data register
		sta	__oper1
		sta	__oper1+1
		rts
?next2:		cpx	#INC_TEST		;increment data test ?
		bne	?next3
		lda	#0			;init data register
		sta	__oper1
		sta	__oper1+1
		rts
?next3:		cpx	#DEC_TEST		;decrement data test ?
		bne	?next4
		lda	#ffh			;init data register
		sta	__oper1
		sta	__oper1+1
		rts
?next4:		cpx	#ALT_TEST		;alternating 1's & 0's test ?
		bne	?next5
		lda	#55h			;init data register
		sta	__oper1
		sta	__oper1+1
		rts
?next5:		cpx	#COM_TEST		;complemented 1's & 0's test ?
		bne	?next6
		lda	#aah			;init data register
		sta	__oper1
		sta	__oper1+1
		rts
?next6:		rts

;	Adjust the test data in '__oper1' depending on the test number
;	in x.

adjust_test_data:  .equal  $
		cpx	#ZERO_TEST		;zero's data test ?
		bne	?next1
		rts				;leave data register alone
?next1:		cpx	#ONE_TEST		;one's data test ?
		bne	?next2
		rts				;leave data register alone
?next2:		cpx	#INC_TEST		;increment data test ?
		bne	?next3
		clc
		lda	__oper1			;adjust data register
		adc	#1
		sta	__oper1
		lda	__oper1+1
		adc	#0
		sta	__oper1+1
		rts
?next3:		cpx	#DEC_TEST		;decrement data test ?
		bne	?next4
		sec
		lda	__oper1			;adjust data register
		sbc	#1
		sta	__oper1
		lda	__oper1+1
		sbc	#0
		sta	__oper1+1
		rts
?next4:		cpx	#ALT_TEST		;alternating 1's & 0's test ?
		bne	?next5
		clc
		lda	__oper1			;adjust data register
		bpl	?4a
		sec
?4a:		rol	__oper1
		lda	__oper1+1
		bpl	?4b
		sec
?4b:		rol	__oper1+1
		rts
?next5:		cpx	#COM_TEST		;complemented 1's & 0's test ?
		bne	?next6
		clc
		lda	__oper1			;adjust data register
		bpl	?5a
		sec
?5a:		rol	__oper1
		lda	__oper1+1
		bpl	?5b
		sec
?5b:		rol	__oper1+1
		rts
?next6:		rts

;	Routine to write and read the RAM.  The test number is in x.

ram_test:	ldx	#.low.write_test_msg	;load lsb of addr of test msg
		ldy	#.high.write_test_msg	;load msb of addr of test msg
		jsr	string_out		;output test msg
		ldx	#.low.addr_backup_msg	;backup before address
		ldy	#.high.addr_backup_msg
		jsr	string_out
		ldy	#2			;first bank is 64k RAM bank #2
		jsr	init_test_data		;initialize rr0 for test
?write_loop1:	lda	#.low.ffffh		;load address of top of ram
		sta	__oper2
		lda	#.high.ffffh
		sta	__oper2+1
?write_loop2:	lda	__oper2			;output enough addresses to keep
		cmp	#ffh			; the numbers scrolling on the
		bne	?skip_addr_out1		; screen
		lda	__oper2+1
		and	#03h
		bne	?skip_addr_out1
		tya				;save bank number
		pha
		txa				;save test #
		pha
		ldx	#.low.addr_backup_msg	;backup before address
		ldy	#.high.addr_backup_msg
		jsr	string_out
		pla				;restore test #
		tax
		pla				;restore bank number
		tay
		jsr	hex_out			;output bank #
		lda	#':'			;separate bank from offset
		jsr	polled_serial_out
		lda	__oper2+1		;load msb of test address
		jsr	hex_out			;output msb of test address
		lda	__oper2			;load lsb of test address
		jsr	hex_out			;output lsb of test address
?skip_addr_out1:jsr	write_test_data		;write high byte of test data
		sec
		lda	__oper2			;decrement test address
		sbc	#1
		sta	__oper2
		lda	__oper2+1
		sbc	#0
		sta	__oper2+1
		jsr	write_test_data		;write low byte of test data
		sec
		lda	__oper2			;decrement test address
		sbc	#1
		sta	__oper2
		lda	__oper2+1
		sbc	#0
		sta	__oper2+1
		lda	__oper2			;check for at address 0fffh
		cmp	#ffh
		bne	?not_end_1
		lda	__oper2+1
		cmp	#0fh
		beq	?end_of_bank1		;loop till bottom of bank
?not_end_1:	jsr	adjust_test_data	;adjust test data
		jmp	?write_loop2
?end_of_bank1:	cpy	#5			;check for last bank
		beq	?end_of_write
		iny				;increment bank #
		jmp	?write_loop1
?end_of_write:	ldy	#30			;load # of backspaces to output
?loop:		lda	#BS			;back up before 'Writing Ram
		jsr	polled_serial_out	; Location' message
		dey
		bne	?loop
		jsr	init_test_data		;initialize test data
		txa				;save test #
		pha
		ldx	#.low.ram_test_msg	;load lsb of addr of test msg
		ldy	#.high.ram_test_msg	;load msb of addr of test msg
		jsr	string_out		;output test msg
		ldx	#.low.addr_backup_msg	;backup before address
		ldy	#.high.addr_backup_msg
		jsr	string_out
		pla				;restore test #
		tax
		lda	#2			;first bank is 64k RAM bank #2
		tay				;xfer bank # -> y
		jsr	hex_out			;output bank #
		lda	#':'			;separate bank from offset
		jsr	polled_serial_out
		lda	#.high.ffffh		;load msb of test address
		jsr	hex_out			;output msb of test address
		lda	#.low.ffffh		;load lsb of test address
		jsr	hex_out			;output lsb of test address
?compare_loop1:	lda	#.low.ffffh		;load address of top of ram
		sta	__oper2
		lda	#.high.ffffh
		sta	__oper2+1
?compare_loop2:	lda	__oper2			;output enough addresses to keep
		cmp	#ffh			; the numbers scrolling on the
		bne	?skip_addr_out2		; screen
		lda	__oper2+1
		and	#03h
		bne	?skip_addr_out2
		tya				;save bank number
		pha
		txa				;save test #
		pha
		ldx	#.low.addr_backup_msg	;backup before address
		ldy	#.high.addr_backup_msg
		jsr	string_out
		pla				;restore test #
		tax
		pla				;restore bank number
		tay
		jsr	hex_out			;output bank #
		lda	#':'			;separate bank from offset
		jsr	polled_serial_out
		lda	__oper2+1		;load msb of test address
		jsr	hex_out			;output msb of test address
		lda	__oper2			;load lsb of test address
		jsr	hex_out			;output lsb of test address
?skip_addr_out2:jsr	read_test_data		;read test data high byte
		cmp	__oper1+1		;compare test data high byte
		bne	?failed_msb
		sec
		lda	__oper2			;decrement test address
		sbc	#1
		sta	__oper2
		lda	__oper2+1
		sbc	#0
		sta	__oper2+1
		jsr	read_test_data		;read test data low byte
		cmp	__oper1			;compare test data low byte
		bne	?failed_lsb
		sec
		lda	__oper2			;decrement test address
		sbc	#1
		sta	__oper2
		lda	__oper2+1
		sbc	#0
		sta	__oper2+1
		lda	__oper2			;check for at address 0fffh
		cmp	#ffh
		bne	?not_end_2
		lda	__oper2+1
		cmp	#0fh
		beq	?end_of_bank2
?not_end_2:	jsr	adjust_test_data	;adjust test data
		jmp	?compare_loop2
?end_of_bank2:	cpy	#5			;check for last bank
		beq	?end_of_test
		iny				;increment bank #
		jmp	?compare_loop1		;compare next bank
?end_of_test:	lda	#0			;clear a, no errors
		rts

;	Here when an error has been detected.  Output the address, the data
;	expected and the data received.

?failed_lsb:	pha				;save bad data
		lda	__oper1			;load good data
		pha				;save good data
		jmp	?failed
?failed_msb:	pha				;save bad data
		lda	__oper1+1		;load good data
		pha				;save good data
?failed:	tya				;save bank #
		pha
		ldx	#.low.mem_failed_msg	;load lsb of addr of failed msg
		ldy	#.high.mem_failed_msg	;load msb of addr of failed msg
		jsr	string_out		;output failed message
		pla				;restore bank #
		pha				;save bank # again
		jsr	hex_out			;output bank #
		lda	#':'			;separate bank from offset
		jsr	polled_serial_out
		lda	__oper2+1		;load msb of test address
		jsr	hex_out			;output msb of test address
		lda	__oper2			;load lsb of test address
		jsr	hex_out			;output lsb of test address
		ldx	#.low.good_data_msg	;ld lsb of addr of good data msg
		ldy	#.high.good_data_msg	;ld msb of addr of good data msg
		jsr	string_out		;output good data message
		pla				;restore bank #
		tay
		pla				;restore good data
		jsr	hex_out			;output good data
		tya				;save bank #
		pha
		ldx	#.low.bad_data_msg	;ld lsb of addr of bad data msg
		ldy	#.high.bad_data_msg	;ld lsb of addr of bad data msg
		jsr	string_out		;output bad data message
		pla				;restore bank #
		tay
		pla				;restore bad data
		jsr	hex_out			;output bad data
		lda	#ffh			;set error flag
		rts

;	Convert the low digit in a to ascii.

hex_ascii:	and	#0fh			;clear high digit
		pha				;save data
		sec
		sbc	#0ah			;check for 0 - 9
		bcs	?a_f
		pla				;restore data
		clc
		adc	#30h
		rts
?a_f:		pla				;restore data
		clc
		adc	#37h
		rts

;	Output the byte in a to the serial port as 2 ascii digits.

hex_out:	pha				;save byte
		ror	a			;convert high digit
		ror	a
		ror	a
		ror	a
		jsr	hex_ascii
		jsr	polled_serial_out	;output high digit
		pla				;restore byte
		jsr	hex_ascii		;convert low digit
		jsr	polled_serial_out	;output low digit
		rts

;	Output the byte in a to the serial port.

polled_serial_out:  .equal  $
		pha
?wait_for_txd:	lda	serial_status
		and	#txd_ready
		beq	?wait_for_txd
		pla
		sta	txd
		rts

;	Output the null terminated string pointed to by y,x to the serial port.

string_out:	lda	__oper1			;save '__oper1'
		pha
		lda	__oper1+1
		pha
		stx	__oper1
		sty	__oper1+1
		ldy	#0			;init index
?string_loop:	lda	(__oper1),y		;load character
		beq	?done
		jsr	polled_serial_out
		iny
		jmp	?string_loop
?done:		pla				;restore '__oper1'
		sta	__oper1+1
		pla
		sta	__oper1
		rts

;	Write the test data in '__oper1' in the location pointed to by
;	'__oper2'.  The bank # is in register y.  If the address to be
;	written is below 2000h, then a diffent routine is called to do
;	the writing to avoid the code that does the writing from being
;	mapped out.

write_test_data:  .equal  $
		txa				;save test #
		pha
		tya				;save bank #
		pha
		lda	__oper2			;load low byte of address
		and	#01h			;check for even or odd address
		bne	?odd
		lda	__oper1			;use lsb of test data for even
		jmp	?even
?odd:		lda	__oper1+1		;use msb of test data for odd
?even:		tax				;xfer test data -> x
		sec
		lda	__oper2			;load destination address lsb
		sbc	#.low.2000h		;check for below 2000h
		lda	__oper2+1
		sbc	#.high.2000h
		bcc	?below_2000h
		jsr	ram_2000_ffff		;map in the proper RAM bank
		ldy	#0			;init index
		txa				;xfer test data -> a
		sta	(__oper2),y		;write test data
		jsr	rom_2000_ffff		;map in the ROM
		jmp	?done
?below_2000h:	jsr	write_2000h		;write test data
?done:		pla				;restore bank #
		tay
		pla				;restore test #
		tax
		rts

		.memory_test_2000h

write_2000h:	lda	#1			;map in RAM from 1000 - 1fff
		sta	map_8_11
		sty	map_addr+1
		ldy	#0			;init index
		txa				;xfer test data -> a
		sta	(__oper2),y		;write test data
		lda	#1			;map in ROM from 1000 - 1fff
		sta	map_8_11
		lda	#0
		sta	map_addr+1
		rts

		.memory_test_section

;	Read the test data from the location pointed to by '__oper2'. The
;	bank # is in register y.  If the address to be read is below 2000h,
;	then a diffent routine is called to do the read too avoid the code
;	that does the reading from being mapped out.

read_test_data:  .equal  $
		tya				;save bank #
		pha
		sec
		lda	__oper2			;load destination address lsb
		sbc	#.low.2000h		;check for below 2000h
		lda	__oper2+1
		sbc	#.high.2000h
		bcc	?below_2000h
		jsr	ram_2000_ffff		;map in the proper RAM bank
		ldy	#0			;init index
		lda	(__oper2),y		;read test data
		sta	__addr_reg		;save test data
		pla				;restore bank #
		tay
		jsr	rom_2000_ffff		;map in the ROM
		jmp	?done
?below_2000h:	jsr	read_2000h		;read test data
		pla				;restore bank #
		tay
?done:		lda	__addr_reg		;restore test data
		rts

		.memory_test_2000h

read_2000h:	lda	#1			;map in RAM from 1000 - 1fff
		sta	map_8_11
		sty	map_addr+1
		ldy	#0			;init index
		lda	(__oper2),y		;read test data
		sta	__addr_reg		;store read data
		lda	#1			;map in ROM from 1000 - 1fff
		sta	map_8_11
		lda	#0
		sta	map_addr+1
		rts

		.memory_test_section

;	Map in RAM from 2000 - ffff.  The bank # is in register y.

ram_2000_ffff:	lda	#2h			;map 2000 - 2fff
		sta	map_8_11
		sty	map_addr+2		;store bank #
		lda	#3h			;map 3000 - 3fff
		sta	map_8_11
		sty	map_addr+3		;store bank #
		lda	#4h			;map 4000 - 4fff
		sta	map_8_11
		sty	map_addr+4		;store bank #
		lda	#5h			;map 5000 - 5fff
		sta	map_8_11
		sty	map_addr+5		;store bank #
		lda	#6h			;map 6000 - 6fff
		sta	map_8_11
		sty	map_addr+6		;store bank #
		lda	#7h			;map 7000 - 7fff
		sta	map_8_11
		sty	map_addr+7		;store bank #
		lda	#8h			;map 8000 - 8fff
		sta	map_8_11
		sty	map_addr+8		;store bank #
		lda	#9h			;map 9000 - 9fff
		sta	map_8_11
		sty	map_addr+9		;store bank #
		lda	#ah			;map a000 - afff
		sta	map_8_11
		sty	map_addr+10		;store bank #
		lda	#bh			;map b000 - bfff
		sta	map_8_11
		sty	map_addr+11		;store bank #
		lda	#ch			;map c000 - cfff
		sta	map_8_11
		sty	map_addr+12		;store bank #
		lda	#dh			;map d000 - dfff
		sta	map_8_11
		sty	map_addr+13		;store bank #
		lda	#eh			;map e000 - efff
		sta	map_8_11
		sty	map_addr+14		;store bank #
		lda	#fh			;map f000 - ffff
		sta	map_8_11
		sty	map_addr+15		;store bank #
		rts

;	Map in ROM from 2000 - ffff.  ROM is bank #0.

rom_2000_ffff:	lda	#2h			;map 2000 - 2fff
		sta	map_8_11
		lda	#0
		sta	map_addr+2		;store bank #
		lda	#3h			;map 3000 - 3fff
		sta	map_8_11
		lda	#0
		sta	map_addr+3		;store bank #
		lda	#4h			;map 4000 - 4fff
		sta	map_8_11
		lda	#0
		sta	map_addr+4		;store bank #
		lda	#5h			;map 5000 - 5fff
		sta	map_8_11
		lda	#0
		sta	map_addr+5		;store bank #
		lda	#6h			;map 6000 - 6fff
		sta	map_8_11
		lda	#0
		sta	map_addr+6		;store bank #
		lda	#7h			;map 7000 - 7fff
		sta	map_8_11
		lda	#0
		sta	map_addr+7		;store bank #
		lda	#8h			;map 8000 - 8fff
		sta	map_8_11
		lda	#0
		sta	map_addr+8		;store bank #
		lda	#9h			;map 9000 - 9fff
		sta	map_8_11
		lda	#0
		sta	map_addr+9		;store bank #
		lda	#ah			;map a000 - afff
		sta	map_8_11
		lda	#0
		sta	map_addr+10		;store bank #
		lda	#bh			;map b000 - bfff
		sta	map_8_11
		lda	#0
		sta	map_addr+11		;store bank #
		lda	#ch			;map c000 - cfff
		sta	map_8_11
		lda	#0
		sta	map_addr+12		;store bank #
		lda	#dh			;map d000 - dfff
		sta	map_8_11
		lda	#0
		sta	map_addr+13		;store bank #
		lda	#eh			;map e000 - efff
		sta	map_8_11
		lda	#0
		sta	map_addr+14		;store bank #
		lda	#fh			;map f000 - ffff
		sta	map_8_11
		lda	#0
		sta	map_addr+15		;store bank #
		rts

;	Test messages.

zero_test_msg:	.byte	CR, LF, "All Zero's Memory Test             : ", 0
one_test_msg:	.byte	CR, LF, "All One's Memory Test              : ", 0
inc_test_msg:	.byte	CR, LF, "Increment Data Memory Test         : ", 0
dec_test_msg:	.byte	CR, LF, "Decrement Data Memory Test         : ", 0
alt_test_msg:	.byte	CR, LF, "Alternating 1's & 0's Memory Test  : ", 0
com_test_msg:	.byte	CR, LF, "Complemented 1's & 0's Memory Test : ", 0
write_test_msg:	.byte	"Writing Ram Location :               ", 0
ram_test_msg:	.byte	"Checking Ram Location :        ", 0
addr_backup_msg:.byte	BS, BS, BS, BS, BS, BS, BS, 0
passed_msg:	.byte	"Passed                         ", 0
mem_failed_msg:	.byte	CR, LF, "Memory Test Failed at Address : ", 0
good_data_msg:	.byte	"   Good Data = ", 0
bad_data_msg:	.byte	"   Bad Data = ", 0

		.ends			;end of memory test code section

		.end

